package com.company;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
//        引用场景：
//        优先使用HashMap，多线程的情况下使用 ConcurrentHashMap(同步)

//        ConcurrentHashMap:同步，效率较好

public class C05ConcurrentMapWithMap {

    private static Map<String, Long> mapWordCounts = new HashMap<>();
    private static ConcurrentMap<String, Long> concurrentMapWordCounts = new ConcurrentHashMap<>();
    public static int count = 0;

    public static long mapIncrease(String word) {
        Long oldValue = mapWordCounts.get(word);
        Long newValue = (oldValue == null) ? 1L : oldValue + 1;
        mapWordCounts.put(word, newValue);
        return newValue;
    }


    public static long ConcurrentMapIncrease(String word) {
        Long oldValue, newValue;
        while (true) {
            oldValue = concurrentMapWordCounts.get(word);
            if (oldValue == null) {
                newValue = 1L;
                //已经有key了就返回放入的值，否则返回空
//（1）如果是新的记录，那么会向map中添加该键值对，并返回null。
//（2）如果已经存在，那么不会覆盖已有的值，直接返回已经存在的值。
                if (concurrentMapWordCounts.putIfAbsent(word, newValue) == null) {
                    break;
                }
            } else {
                newValue = oldValue + 1;
                //值替换，每次替换时都会比较上面拿到oldValue是否就是当前map里面的值，是才替换，否则继续获取
                if (concurrentMapWordCounts.replace(word, oldValue, newValue)) {
                    break;
                }
            }
        }
        return newValue;
    }

    public static void mapWordCount() throws InterruptedException, ExecutionException {
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.mapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000) ;
                C05ConcurrentMapWithMap.mapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.mapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.mapIncrease("work");
            }
        }).start();
    }

    public static void concurrentWordCount() throws InterruptedException, ExecutionException {
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.ConcurrentMapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.ConcurrentMapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.ConcurrentMapIncrease("work");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                int count = 0;
                while (count++ < 10000)
                    C05ConcurrentMapWithMap.ConcurrentMapIncrease("work");
            }
        }).start();
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        C05ConcurrentMapWithMap.mapWordCount();
        Thread.sleep(10000);
        System.out.println("final count map" + C05ConcurrentMapWithMap.mapWordCounts.get("work"));//多线程累加，每次都少于40000，故线程不安全
        C05ConcurrentMapWithMap.concurrentWordCount();

        Thread.sleep(10000);
        System.out.println("final count concurrentMap" + C05ConcurrentMapWithMap.concurrentMapWordCounts.get("work"));//多线程累加，每次都是40000
    }
}

//
//————————————————
//    版权声明：本文为CSDN博主「攻城狮Luke（刘健彬）」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
//    原文链接：https://blog.csdn.net/u010739551/article/details/78655695